Skip to content

Add reusable IFC policy engine - #7001

Open
jmecom wants to merge 1 commit into
mainfrom
jm/ifc-engine-library
Open

Add reusable IFC policy engine#7001
jmecom wants to merge 1 commit into
mainfrom
jm/ifc-engine-library

Conversation

@jmecom

@jmecom jmecom commented Aug 28, 2026

Copy link
Copy Markdown
Collaborator

Adds buzz-ifc, a zero-I/O Rust library that implements the audience-, context-, agent-, and epoch-scoped policy from the secure agent information-flow design.

  • Derives execution domains from verified Buzz facts and produces stable worker-routing keys.
  • Enforces read, capability, process-reuse, confinement, publication, and exact declassification decisions.
  • Validates Nostr principals as x-only secp256k1 points and fails closed across realms, contexts, unknown provenance, and reused processes.

This intentionally does not integrate with ACP, the relay, Desktop, or a broker executable. The trusted broker can consume the library while retaining responsibility for verifying events and membership and for durable declassification expiry/replay enforcement.

Checked with just ci, targeted cargo test -p buzz-ifc, Clippy with warnings denied, and rustdoc with warnings denied.

Signed-off-by: Jordan Mecom <jm@squareup.com>
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

🔐 Codex Security Review

Status: review required for the current range.

The current range is e09f715c9d0ee2cb7bf8a39061e601f3a502f588...4c2de983fcd8a7aa1c1f71629dcd873332d665d2.
A new review must complete for this exact range. When manual authorization
is required, a Block organization member must comment exactly
@buzz-security-review 4c2de983fcd8a7aa1c1f71629dcd873332d665d2 to authorize a new review.
Any previous review applies only to its recorded range.

@jmecom
jmecom marked this pull request as ready for review September 4, 2026 18:36
@jmecom
jmecom requested a review from a team as a code owner September 4, 2026 18:36
@TheSentinel454

Copy link
Copy Markdown
Contributor

Reviewed exact head 4c2de983fcd8a7aa1c1f71629dcd873332d665d2. The zero-I/O policy core is a good architectural boundary, but its public API currently permits states that bypass its documented confinement invariants.

P0 — first foreign-realm observation does not poison confinement

ConfinementState::observe stores the first label directly and only sets cross_realm when joining a later label fails (crates/buzz-ifc/src/policy.rs:85-107). Publication checks that boolean before evaluating an exact grant (policy.rs:166-190).

The concrete bypass is ResourceLabel::trusted_configuration: it carries a realm-bearing confidentiality label but uses the realm-less TrustedConfiguration context (domain.rs:145-150,547-553), which DomainContext::permits accepts universally (domain.rs:100-103). If a realm-B trusted-configuration value is the first observation in a realm-A process, confinement does not record the mismatch and a matching declassification grant can authorize output.

Please bind confinement to the entered domain's realm, or independently track the first observed realm and permanently poison state on any mismatch. Add a regression test where a realm-B trusted-configuration label is the first/only observation in a realm-A process and an otherwise valid exact grant still cannot publish.

P0 — verified grants admit impossible destination shapes

DeclassificationGrant::verify authenticates the approver and signature but never validates destination against destination_context (crates/buzz-ifc/src/declassification.rs:61-102). matches then checks exact equality only (:105-124), and ProcessState::publish accepts a matching grant before ordinary destination checks (policy.rs:182-195).

A signed realm-B audience paired with a realm-A routing context—or a public audience paired with a private conversation context—can therefore authorize a release. ExecutionDomain::new rejects these same realm and audience/context mismatches (domain.rs:401-420), so grants currently bypass an existing domain invariant.

Please extract one shared destination-shape validator, use it for both domain construction and grant verification, and return a distinct malformed-destination error. Add regression tests for cross-realm audience/context and public/private shape mismatches.

P0 — Clone allows rollback of monotonic process taint

ProcessState is documented as the security history of one actual process, but both it and ConfinementState derive Clone (policy.rs:85,110-121). A caller can preserve a clean clone, observe restricted or foreign input on the live copy, then evaluate publication through the stale copy. The type therefore does not guarantee that security state grows monotonically with everything the process has observed.

Please remove Clone from both state types. If diagnostics need snapshots, expose a separate read-only summary that has no publish method. Add a compile-fail/API test proving ProcessState is not cloneable, while retaining runtime coverage that observations permanently constrain later publication.

P1 — realm identity hashes noncanonical relay URL spellings

RealmId::from_relay_url hashes the caller's raw string (crates/buzz-ifc/src/label.rs:47-59). Buzz's sole runtime relay-identity normalizer canonicalizes case, default ports, loopback spellings, and root slash (crates/buzz-core/src/relay.rs:26-37,84-103). Equivalent identities such as WSS://Relay.Example:443/ and wss://relay.example therefore become different realms, fragmenting domain and worker-routing keys based only on spelling.

Please consume a canonical relay identity, reuse the shared normalizer, or make realm construction fallible and apply the same canonicalization. Pin all equivalences already tested in buzz-core/src/relay.rs, while keeping distinct hosts and non-root paths distinct.

These are 3 P0, 1 P1 under Buzz PR Review Criteria v0: the P0s cross trust/provenance boundaries in the new security substrate; the P1 creates deterministic false isolation. Package tests, Clippy, and rustdoc are green at this head, but those tests do not cover these cases. The reworked head should also receive an independent external-consumer API exercise before landing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants